package com.md.config.database;

import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.md.value.server.DataSourceContextHolder;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.HexValue;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SetOperationList;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * @author 刘骄阳
 * 2023-12-20 15:41
 */
@AllArgsConstructor
@Slf4j
public class MyDataPermission extends JsqlParserSupport implements InnerInterceptor {
  /**
   * 操作前置处理
   * <p>
   * 改改sql啥的
   *
   * @param executor      Executor(可能是代理对象)
   * @param ms            MappedStatement
   * @param parameter     parameter
   * @param rowBounds     rowBounds
   * @param resultHandler resultHandler
   * @param boundSql      boundSql
   */
  @Override
  public void beforeQuery(final Executor executor, final MappedStatement ms,
                          final Object parameter, final RowBounds rowBounds,
                          final ResultHandler resultHandler, final BoundSql boundSql) {
    DataSourceContextHolder.read();
    String id = ms.getId();
    if (InterceptorIgnoreHelper.willIgnoreBlockAttack(id)) {
      return;
    }
    String className = id.substring(0, id.lastIndexOf("."));
    PluginUtils.MPBoundSql sql = PluginUtils.mpBoundSql(boundSql);
    String finalSql = this.parserSingle(sql.sql(), id);
    sql.sql(finalSql);
  }


  /**
   * 拼接查询sql条件
   */
  @Override
  protected void processSelect(final Select select, final int index, final String sql, final Object obj) {
    SelectBody selectBody = select.getSelectBody();
    if (selectBody instanceof PlainSelect) {
      this.setWhere((PlainSelect) selectBody, (String) obj);
    } else if (selectBody instanceof SetOperationList) {
      SetOperationList setOperationList = (SetOperationList) selectBody;
      List<SelectBody> selectBodyList = setOperationList.getSelects();
      selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
    }
  }

  private void setWhere(final PlainSelect plainSelect, final String whereSegment) {
    Expression where = plainSelect.getWhere();
    if (where == null) {
      where = new HexValue(" 1 = 1 ");
    }
    //获取mapper名称
    String className = whereSegment.substring(0, whereSegment.lastIndexOf("."));
    //获取方法名
    String methodName = whereSegment.substring(whereSegment.lastIndexOf(".") + 1);
    Table fromItem = (Table) plainSelect.getFromItem();
    // 有别名用别名，无别名用表名，防止字段冲突报错
    Alias fromItemAlias = fromItem.getAlias();
    String mainTableName = fromItemAlias == null ? null : fromItemAlias.getName();
    log.info("interceptor begin,where :{},className:{},methodName:{}", where, className, methodName);

    //获取当前mapper 的方法
    try {
      Method[] methods = Class.forName(className).getMethods();
      //遍历判断mapper 的所以方法，判断方法上是否有 DataScope注解
      for (Method m : methods) {
        if (Objects.equals(m.getName(), methodName)) {
          // 部门条件拼接
          Expression andExpression = new HexValue(" 1 = 1 ");
          // 查看未删除的数据
          EqualsTo usesEqualsTo = new EqualsTo();
          usesEqualsTo.setLeftExpression(new Column(mainTableName == null ? "enable" : mainTableName + ".enable"));
          usesEqualsTo.setRightExpression(new LongValue(0));
          IsNullExpression nullExpression = new IsNullExpression();
          nullExpression.withLeftExpression(new Column(mainTableName == null ? "enable" : mainTableName + ".enable"));
          // ()括号拼接
          Parenthesis parenthesis = new Parenthesis(new OrExpression(usesEqualsTo, nullExpression));
//          AndExpression expression = new AndExpression(where, parenthesis);
//          plainSelect.setWhere(new AndExpression(expression, andExpression));
          plainSelect.setWhere(new AndExpression(where, andExpression));
          log.info("interceptor end,where :{}", plainSelect);
          break;
        }
      }
    } catch (ClassNotFoundException e) {
      log.error("设置条件失败: {}", e.getMessage(), e);
    }
  }

  @Override
  public void beforeUpdate(final Executor executor, final MappedStatement ms, final Object parameter) {
    DataSourceContextHolder.write();
    // 获取SQL语句
    BoundSql boundSql = ms.getBoundSql(parameter);
    String sql = boundSql.getSql();

    // 打印SQL语句
    System.err.println("Executing SQL: " + sql);
  }

  public String appendSQLMark(final PlainSelect plainSelect, final String whereSegment) {
    Expression where = plainSelect.getWhere();
    if (where == null) {
      where = new HexValue(" 1 = 1 ");
    }
    //获取mapper名称
    String className = whereSegment.substring(0, whereSegment.lastIndexOf("."));
    //获取方法名
    String methodName = whereSegment.substring(whereSegment.lastIndexOf(".") + 1);
    Table fromItem = (Table) plainSelect.getFromItem();
    // 有别名用别名，无别名用表名，防止字段冲突报错
    Alias fromItemAlias = fromItem.getAlias();
    String mainTableName = fromItemAlias == null ? null : fromItemAlias.getName();
    log.info("interceptor begin,where :{},className:{},methodName:{}", where, className, methodName);

    //获取当前mapper 的方法
    try {
      Method[] methods = Class.forName(className).getMethods();
      //遍历判断mapper 的所以方法，判断方法上是否有 DataScope注解
      for (Method m : methods) {
        if (Objects.equals(m.getName(), methodName)) {
          // 部门条件拼接
          Expression andExpression = new HexValue(" 1 = 1 ");
          // 查看未删除的数据
          EqualsTo usesEqualsTo = new EqualsTo();
          usesEqualsTo.setLeftExpression(new Column(mainTableName == null ? "enable" : mainTableName + ".enable"));
          usesEqualsTo.setRightExpression(new LongValue(0));
          IsNullExpression nullExpression = new IsNullExpression();
          nullExpression.withLeftExpression(new Column(mainTableName == null ? "enable" : mainTableName + ".enable"));
          // ()括号拼接
          Parenthesis parenthesis = new Parenthesis(new OrExpression(usesEqualsTo, nullExpression));
//          AndExpression expression = new AndExpression(where, parenthesis);
//          plainSelect.setWhere(new AndExpression(expression, andExpression));
          plainSelect.setWhere(new AndExpression(where, andExpression));
          log.info("interceptor end,where :{}", plainSelect);
          break;
        }
      }
    } catch (ClassNotFoundException e) {
      log.error("设置条件失败: {}", e.getMessage(), e);
    }
    return null;
  }
}
